package cn.smp.client;

import cn.smp.message.RpcRequestMessage;
import cn.smp.protocol.MessageCodecSharable;
import cn.smp.protocol.ProcaotolFrameDecoder;
import cn.smp.client.handler.RpcResponseMessageHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

/**
 * 客户端
 * 写消息->出站顺序处理
 * @see ChannelOutboundHandler implements
 *
 * 读消息—>入站顺序处理
 * @see ChannelInboundHandler implements
 */
@Slf4j
public class RpcClient {
    public static void main(String[] args) {
        final LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.DEBUG);
        final MessageCodecSharable MESSAGE_CODEC = new MessageCodecSharable();
        //rpc响应消息处理
        final RpcResponseMessageHandler RPC_HANDLER = new RpcResponseMessageHandler();

        final NioEventLoopGroup worker = new NioEventLoopGroup();
        final Bootstrap bootstrap = new Bootstrap();
        bootstrap.channel(NioSocketChannel.class);
        bootstrap.group(worker);
        bootstrap.handler(new ChannelInitializer<SocketChannel>() {
            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ch.pipeline().addLast(new ProcaotolFrameDecoder());
                ch.pipeline().addLast(LOGGING_HANDLER);
                ch.pipeline().addLast(MESSAGE_CODEC);
                ch.pipeline().addLast(RPC_HANDLER);
            }
        });
        try {
            final Channel channel = bootstrap.connect("localhost", 8080).sync().channel();

            final ChannelFuture future = channel.writeAndFlush(new
                    RpcRequestMessage(
                    1,
                    "cn.smp.server.service.HelloService",
                    "sayHello",
                    String.class,
                    new Class[]{String.class},
                    new Object[]{"张三"}));

            future.addListener(promise -> {
                if (!promise.isSuccess()) {
                    final Throwable cause = promise.cause();
                    log.error("error",cause);
                }
            });

            channel.closeFuture().sync();
        } catch (InterruptedException e) {
            log.error("client error",e);
        }finally {
            worker.shutdownGracefully();
        }
    }
}
